package ua.edu.nuos.tees.jdmmon.gui;

import jssc.SerialPortException;
import ua.edu.nuos.tees.jdmmon.bl.MultimeterService;
import ua.edu.nuos.tees.jdmmon.dao.exceptions.ConfigException;
import ua.edu.nuos.tees.jdmmon.gui.charts.ThreePhaseChart;
import ua.edu.nuos.tees.jdmmon.gui.components.*;
import ua.edu.nuos.tees.jdmmon.gui.dialogs.ConnectionDialog;
import ua.edu.nuos.tees.jdmmon.gui.dialogs.SettingsDialog;
import ua.edu.nuos.tees.jdmmon.helpers.ResourceLocator;
import ua.edu.nuos.tees.jdmmon.vo.MultimeterVo;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;

/**
 * Graphical user interface
 *
 * @author Olha Mudrievska
 *         08.05.13
 */
public class GUI implements ActionListener {

    private final Dimension defaultDimension = new Dimension(1200, 890);
    private JFrame jFrame;
    private final static boolean RIGHT_TO_LEFT = false;
    private static AnalogArrowIndicator currentAnalogIndicatorL1;
    private static AnalogArrowIndicator currentAnalogIndicatorL2;
    private static AnalogArrowIndicator currentAnalogIndicatorL3;
    private static AnalogArrowIndicator voltageAnalogIndicatorL1;
    private static AnalogArrowIndicator voltageAnalogIndicatorL2;
    private static AnalogArrowIndicator voltageAnalogIndicatorL3;
    private static AnalogArrowIndicator cosPhiAnalogIndicatorL1;
    private static AnalogArrowIndicator cosPhiAnalogIndicatorL2;
    private static AnalogArrowIndicator cosPhiAnalogIndicatorL3;
    private static AnalogArrowIndicator frequency;
    private static DigitalIndicator voltageDigitalIndicatorL1_L2;
    private static DigitalIndicator voltageDigitalIndicatorL2_L3;
    private static DigitalIndicator voltageDigitalIndicatorL3_L1;
    private static ScaleIndicator scaleActivePowerIndicator;
    private static ScaleIndicator scaleReactivePowerIndicator;
    private static ScaleIndicator scaleApparentPowerIndicator;
    private JPanel leftPanel;
    private Logotype logotype;
    private static MultimeterVo multimeterVo;
    private static MultimeterService multimeterService;
    private static boolean currentL1L2L3ChartEnabled = false;
    private static boolean voltageL1L2L3ChartEnabled = false;
    private static boolean phaseToPhaseL1L2L3ChartEnabled = false;
    private static ThreePhaseChart voltageL1L2L3Chart;
    private static ThreePhaseChart currentL1L2L3Chart;
    private static ThreePhaseChart phaseToPhaseL1L2L3Chart;
    private MouseListener voltageMouseListener;
    private MouseListener currentMouseListener;
    private MouseListener phaseToPhaseMouseListener;
    private MultimeterVo bufferedMultimeterVo;

    public GUI(MultimeterService multimeterService) throws IOException, ConfigException, SerialPortException, exceptions.ConfigException {
        this.multimeterService = multimeterService;
        bufferedMultimeterVo = MultimeterVo.createNewInstance();
        jFrame = new JFrame("Jdmmon");
        jFrame.setSize(defaultDimension);
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        MenuBar();
        addComponentsToPane(jFrame.getContentPane());
        jFrame.setVisible(true);
        jFrame.setLocationRelativeTo(null);
    }

    void MenuBar() {
        JMenuBar jMenuBar = new JMenuBar();

        JMenu jMenuFile = new JMenu("File");

        JMenuItem jMenuItemExit = new JMenuItem("Exit");
        jMenuItemExit.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        jMenuFile.add(jMenuItemExit);
        jMenuBar.add(jMenuFile);

        JMenu jMenuConfiguration = new JMenu("Settings");
        JMenuItem jMenuItemSetConfiguration = new JMenuItem("Set configuration ...");
        jMenuItemSetConfiguration.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                createSettingsDialog(true);
            }
        });
        jMenuConfiguration.add(jMenuItemSetConfiguration);
        jMenuBar.add(jMenuConfiguration);

        JMenu jMenuConnect = new JMenu("Connect");
        JMenuItem jMenuItemConnect = new JMenuItem("Connect...");
        jMenuItemConnect.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                createConnectionDialog(true);
            }
        });
        jMenuConnect.add(jMenuItemConnect);
        jMenuBar.add(jMenuConnect);

        JMenu jMenuHelp = new JMenu("Help");
        JMenuItem jMenuItemAbout = new JMenuItem("About");
        jMenuItemAbout.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JDialog aboutDialog = new JDialog();
                aboutDialog.setTitle("About");
                JTextArea aboutArea = new JTextArea();

                aboutArea.setBackground(new Color (238, 238, 238));
                aboutArea.setFont(new Font("Arial", Font.PLAIN, 14));
                aboutArea.setText("\n  Jdmmon Version: 1.0-SNAPSHOT\n\n" +
                        "  Authors: Timur Yarosh\n" +
                        "                 Olga Mudrievskaya\n\n" +
                        "  National University of shipbuilding\n\n" +
                        "  Kathedra: Theoretical electrotechnics\n" +
                        "                 and electronic systems ");
                aboutArea.setEditable(false);
                aboutDialog.add(aboutArea);
                aboutDialog.setSize(290, 230);
                aboutDialog.setResizable(false);
                aboutDialog.setLocationRelativeTo(null);
                aboutDialog.setVisible(true);
            }
        });
        jMenuHelp.add(jMenuItemAbout);
        jMenuBar.add(jMenuHelp);

        jFrame.setJMenuBar(jMenuBar);
    }

    public static void createConnectionDialog(boolean state) {
        ConnectionDialog connectionDialog = new ConnectionDialog(state);
        if (state)
            connectionDialog.setDao(multimeterService);
        connectionDialog.setSize(250, 290);
        connectionDialog.setTitle("Connect");
        connectionDialog.setResizable(false);
        connectionDialog.setLocationRelativeTo(null);
        connectionDialog.setVisible(true);
    }

    public static void createSettingsDialog(boolean state) {
        SettingsDialog settingsDialog = new SettingsDialog(state);
        if (state)
            settingsDialog.setDao(multimeterService);
        settingsDialog.setSize(250, 200);
        settingsDialog.setTitle("Set configuration");
        settingsDialog.setResizable(false);
        settingsDialog.setLocationRelativeTo(null);
        settingsDialog.setVisible(true);
    }

    public void actionPerformed(ActionEvent actionEvent) {
        String comStr = actionEvent.getActionCommand();
        if (comStr.equals("Exit")) System.exit(0);
    }

    public void addComponentsToPane(Container pane) throws IOException {
        if (RIGHT_TO_LEFT) {
            pane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
        }
        pane.setLayout(new GridBagLayout());

        ResourceLocator resourceLocator = new ResourceLocator();
        scaleActivePowerIndicator = new ScaleIndicator(resourceLocator.locateByPath
                ("/images/ScaleActivePowerIndicator.png"), 300000);
        scaleReactivePowerIndicator = new ScaleIndicator(resourceLocator.locateByPath
                ("/images/ScaleReactivePowerIndicator.png"), 300000);
        scaleApparentPowerIndicator = new ScaleIndicator(resourceLocator.locateByPath
                ("/images/ScaleApparentPowerIndicator.png"), 400000);
        voltageAnalogIndicatorL1 = new AnalogArrowIndicator(resourceLocator.locateByPath
                ("/images/AnalogVoltageIndicatorL1.png"), 142, 165, 123, 0, 500, Math.PI, Math.PI * 1.5);
        voltageAnalogIndicatorL2 = new AnalogArrowIndicator(resourceLocator.locateByPath
                ("/images/AnalogVoltageIndicatorL2.png"), 142, 165, 123, 0, 500, Math.PI, Math.PI * 1.5);
        voltageAnalogIndicatorL3 = new AnalogArrowIndicator(resourceLocator.locateByPath
                ("/images/AnalogVoltageIndicatorL3.png"), 142, 165, 123, 0, 500, Math.PI, Math.PI * 1.5);
        frequency = new AnalogArrowIndicator(resourceLocator.locateByPath
                ("/images/Frequency.png"), 83, 111, 68, 0, 100, Math.PI * 0.75, Math.PI * 2.25);
        currentAnalogIndicatorL1 = new AnalogArrowIndicator(resourceLocator.locateByPath
                ("/images/AnalogCurrentIndicatorL1.png"), 142, 165, 123, 0, 500, Math.PI, Math.PI * 1.5);
        currentAnalogIndicatorL2 = new AnalogArrowIndicator(resourceLocator.locateByPath
                ("/images/AnalogCurrentIndicatorL2.png"), 142, 165, 123, 0, 500, Math.PI, Math.PI * 1.5);
        currentAnalogIndicatorL3 = new AnalogArrowIndicator(resourceLocator.locateByPath
                ("/images/AnalogCurrentIndicatorL3.png"), 142, 165, 123, 0, 500, Math.PI, Math.PI * 1.5);
        voltageDigitalIndicatorL1_L2 = new DigitalIndicator(resourceLocator.locateByPath
                ("/images/DigitalVoltageIndicatorL1-L2.png"));
        voltageDigitalIndicatorL2_L3 = new DigitalIndicator(resourceLocator.locateByPath
                ("/images/DigitalVoltageIndicatorL2-L3.png"));
        voltageDigitalIndicatorL3_L1 = new DigitalIndicator(resourceLocator.locateByPath
                ("/images/DigitalVoltageIndicatorL3-L1.png"));
        cosPhiAnalogIndicatorL1 = new AnalogArrowIndicator(resourceLocator.locateByPath
                ("/images/AnalogPowerFactorIndicatorL1.png"), 83, 111, 68, 0, 1, Math.PI * 0.75, Math.PI * 1.5);
        cosPhiAnalogIndicatorL2 = new AnalogArrowIndicator(resourceLocator.locateByPath
                ("/images/AnalogPowerFactorIndicatorL2.png"), 83, 111, 68, 0, 1, Math.PI * 0.75, Math.PI * 1.5);
        cosPhiAnalogIndicatorL3 = new AnalogArrowIndicator(resourceLocator.locateByPath
                ("/images/AnalogPowerFactorIndicatorL3.png"), 83, 111, 68, 0, 1, Math.PI * 0.75, Math.PI * 1.5);
        logotype = new Logotype(resourceLocator.locateByPath("/images/Logotype.png"));
        leftPanel = new JPanel();

        addPanel(leftPanel, pane, GridBagConstraints.BOTH, 1, 2, 0.25, 1.0, 1, 0);
        addPanel(logotype, pane, GridBagConstraints.BOTH, 1, 1, 0.5, 1.0, 0, 0);
        addPanel(scaleActivePowerIndicator, pane, GridBagConstraints.BOTH, 1, 2, 0.25, 1.0, 2, 0);
        addPanel(scaleReactivePowerIndicator, pane, GridBagConstraints.BOTH, 1, 2, 0.25, 1.0, 3, 0);
        addPanel(scaleApparentPowerIndicator, pane, GridBagConstraints.BOTH, 1, 2, 0.25, 1.0, 4, 0);
        addPanel(voltageAnalogIndicatorL1, pane, GridBagConstraints.BOTH, 1, 1, 0.4, 1.0, 5, 0);
        addPanel(voltageAnalogIndicatorL2, pane, GridBagConstraints.BOTH, 1, 1, 0.4, 1.0, 6, 0);
        addPanel(voltageAnalogIndicatorL3, pane, GridBagConstraints.BOTH, 1, 1, 0.4, 1.0, 7, 0);
        addPanel(frequency, pane, GridBagConstraints.BOTH, 1, 1, 0.5, 1.0, 0, 1);
        addPanel(currentAnalogIndicatorL1, pane, GridBagConstraints.BOTH, 1, 1, 0.4, 1.0, 5, 1);
        addPanel(currentAnalogIndicatorL2, pane, GridBagConstraints.BOTH, 1, 1, 0.4, 1.0, 6, 1);
        addPanel(currentAnalogIndicatorL3, pane, GridBagConstraints.BOTH, 1, 1, 0.4, 1.0, 7, 1);
        addPanel(voltageDigitalIndicatorL1_L2, pane, GridBagConstraints.BOTH, 1, 1, 0.5, 1.0, 0, 2);
        addPanel(voltageDigitalIndicatorL2_L3, pane, GridBagConstraints.BOTH, 2, 1, 0.5, 1.0, 1, 2);
        addPanel(voltageDigitalIndicatorL3_L1, pane, GridBagConstraints.BOTH, 2, 1, 0.5, 1.0, 3, 2);
        addPanel(cosPhiAnalogIndicatorL1, pane, GridBagConstraints.BOTH, 1, 1, 0.4, 1.0, 5, 2);
        addPanel(cosPhiAnalogIndicatorL2, pane, GridBagConstraints.BOTH, 1, 1, 0.4, 1.0, 6, 2);
        addPanel(cosPhiAnalogIndicatorL3, pane, GridBagConstraints.BOTH, 1, 1, 0.4, 1.0, 7, 2);

        voltageMouseListener = new MouseListener() {
            public void mousePressed(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON1) {
                    voltageL1L2L3Chart = new ThreePhaseChart("Phase Voltage Chart", "Phase voltage");
                    voltageL1L2L3Chart.pack();
                    voltageL1L2L3Chart.setLocationRelativeTo(null);
                    voltageL1L2L3Chart.setVisible(true);
                    voltageL1L2L3Chart.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
                    voltageL1L2L3ChartEnabled = true;
                }
            }

            public void mouseClicked(MouseEvent e) {
            }

            public void mouseReleased(MouseEvent e) {
            }

            public void mouseEntered(MouseEvent e) {
            }

            public void mouseExited(MouseEvent e) {
            }
        };
        voltageAnalogIndicatorL1.addMouseListener(voltageMouseListener);
        voltageAnalogIndicatorL2.addMouseListener(voltageMouseListener);
        voltageAnalogIndicatorL3.addMouseListener(voltageMouseListener);

        currentMouseListener = new MouseListener() {
            public void mousePressed(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON1) {
                    currentL1L2L3Chart = new ThreePhaseChart("Phase Current Chart", "Phase current");
                    currentL1L2L3Chart.pack();
                    currentL1L2L3Chart.setLocationRelativeTo(null);
                    currentL1L2L3Chart.setVisible(true);
                    currentL1L2L3Chart.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
                    currentL1L2L3ChartEnabled = true;
                }
            }

            public void mouseClicked(MouseEvent e) {
            }

            public void mouseReleased(MouseEvent e) {
            }

            public void mouseEntered(MouseEvent e) {
            }

            public void mouseExited(MouseEvent e) {
            }
        };
        currentAnalogIndicatorL1.addMouseListener(currentMouseListener);
        currentAnalogIndicatorL2.addMouseListener(currentMouseListener);
        currentAnalogIndicatorL3.addMouseListener(currentMouseListener);

        phaseToPhaseMouseListener = new MouseListener() {
            public void mousePressed(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON1) {
                    phaseToPhaseL1L2L3Chart = new ThreePhaseChart("Phase To Phase Voltage Chart",
                            "Phase to phase voltage");
                    phaseToPhaseL1L2L3Chart.pack();
                    phaseToPhaseL1L2L3Chart.setLocationRelativeTo(null);
                    phaseToPhaseL1L2L3Chart.setVisible(true);
                    phaseToPhaseL1L2L3Chart.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
                    phaseToPhaseL1L2L3ChartEnabled = true;
                }
            }

            public void mouseClicked(MouseEvent e) {
            }

            public void mouseReleased(MouseEvent e) {
            }

            public void mouseEntered(MouseEvent e) {
            }

            public void mouseExited(MouseEvent e) {
            }
        };
        voltageDigitalIndicatorL1_L2.addMouseListener(phaseToPhaseMouseListener);
        voltageDigitalIndicatorL2_L3.addMouseListener(phaseToPhaseMouseListener);
        voltageDigitalIndicatorL3_L1.addMouseListener(phaseToPhaseMouseListener);

    }

    /**
     * Add panel to container
     *
     * @param fill       The initial fill value.
     * @param gridx      The initial gridx value.
     * @param gridy      The initial gridy value.
     * @param gridwidth  The initial gridwidth value.
     * @param gridheight The initial gridheight value.
     * @param weightx    The initial weightx value.
     * @param weighty    The initial weighty value.
     */
    private void addPanel(JPanel indicator, Container pane, int fill, int gridwidth, int gridheight,
                          double weightx, double weighty, int gridx, int gridy) {
        GridBagConstraints gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.fill = fill;
        gridBagConstraints.gridwidth = gridwidth;
        gridBagConstraints.gridheight = gridheight;
        gridBagConstraints.weightx = weightx;
        gridBagConstraints.weighty = weighty;
        gridBagConstraints.gridx = gridx;
        gridBagConstraints.gridy = gridy;
        pane.add(indicator, gridBagConstraints);
    }

    /**
     * Refresh all value setters
     *
     * @throws InterruptedException
     * @throws SerialPortException
     * @throws IOException
     */
    public void refreshGUI() throws InterruptedException, SerialPortException, IOException {
        multimeterService.refreshData();
        multimeterVo = MultimeterVo.getInstance();
        if (multimeterVo.getPhaseCurrentL1() <= 50000)
            bufferedMultimeterVo.setPhaseCurrentL1(multimeterVo.getPhaseCurrentL1());
        if (multimeterVo.getPhaseCurrentL2() <= 50000)
            bufferedMultimeterVo.setPhaseCurrentL2(multimeterVo.getPhaseCurrentL2());
        if (multimeterVo.getPhaseCurrentL3() <= 50000)
            bufferedMultimeterVo.setPhaseCurrentL3(multimeterVo.getPhaseCurrentL3());
        if (multimeterVo.getPhaseVoltageL1() <= 500)
            bufferedMultimeterVo.setPhaseVoltageL1(multimeterVo.getPhaseVoltageL1());
        if (multimeterVo.getPhaseVoltageL2() <= 500)
            bufferedMultimeterVo.setPhaseVoltageL2(multimeterVo.getPhaseVoltageL2());
        if (multimeterVo.getPhaseVoltageL3() <= 500)
            bufferedMultimeterVo.setPhaseVoltageL3(multimeterVo.getPhaseVoltageL3());
        if (multimeterVo.getCosPhiL1() <= 100)
            bufferedMultimeterVo.setCosPhiL1(multimeterVo.getCosPhiL1());
        if (multimeterVo.getCosPhiL2() <= 100)
            bufferedMultimeterVo.setCosPhiL2(multimeterVo.getCosPhiL2());
        if (multimeterVo.getCosPhiL3() <= 100)
            bufferedMultimeterVo.setCosPhiL3(multimeterVo.getCosPhiL3());
        if (multimeterVo.getTotalActivePower() <= 300000)
            bufferedMultimeterVo.setTotalActivePower(multimeterVo.getTotalActivePower());
        if (multimeterVo.getTotalReactivePower() <= 300000)
            bufferedMultimeterVo.setTotalReactivePower(multimeterVo.getTotalReactivePower());
        if (multimeterVo.getTotalApparentPower() <= 400000)
            bufferedMultimeterVo.setTotalApparentPower(multimeterVo.getTotalApparentPower());
        if (multimeterVo.getPhaseToPhaseVoltageL1L2() <= 500)
            bufferedMultimeterVo.setPhaseToPhaseVoltageL1L2(multimeterVo.getPhaseToPhaseVoltageL1L2());
        if (multimeterVo.getPhaseToPhaseVoltageL2L3() <= 500)
            bufferedMultimeterVo.setPhaseToPhaseVoltageL2L3(multimeterVo.getPhaseToPhaseVoltageL2L3());
        if (multimeterVo.getPhaseToPhaseVoltageL3L1() <= 500)
            bufferedMultimeterVo.setPhaseToPhaseVoltageL3L1(multimeterVo.getPhaseToPhaseVoltageL3L1());
        if (multimeterVo.getFrequency() <= 1000)
            bufferedMultimeterVo.setFrequency(multimeterVo.getFrequency());

        currentAnalogIndicatorL1.setValue(bufferedMultimeterVo.getPhaseCurrentL1() / 100.0);
        currentAnalogIndicatorL2.setValue(bufferedMultimeterVo.getPhaseCurrentL2() / 100.0);
        currentAnalogIndicatorL3.setValue(bufferedMultimeterVo.getPhaseCurrentL3() / 100.0);
        voltageAnalogIndicatorL1.setValue(bufferedMultimeterVo.getPhaseVoltageL1());
        voltageAnalogIndicatorL2.setValue(bufferedMultimeterVo.getPhaseVoltageL2());
        voltageAnalogIndicatorL3.setValue(bufferedMultimeterVo.getPhaseVoltageL3());
        cosPhiAnalogIndicatorL1.setValue(bufferedMultimeterVo.getCosPhiL1() / 100.0);
        cosPhiAnalogIndicatorL2.setValue(bufferedMultimeterVo.getCosPhiL2() / 100.0);
        cosPhiAnalogIndicatorL3.setValue(bufferedMultimeterVo.getCosPhiL3() / 100.0);
        scaleActivePowerIndicator.setValue(bufferedMultimeterVo.getTotalActivePower());
        scaleReactivePowerIndicator.setValue(bufferedMultimeterVo.getTotalReactivePower());
        scaleApparentPowerIndicator.setValue(bufferedMultimeterVo.getTotalApparentPower());
        voltageDigitalIndicatorL1_L2.setValue(bufferedMultimeterVo.getPhaseToPhaseVoltageL1L2());
        voltageDigitalIndicatorL2_L3.setValue(bufferedMultimeterVo.getPhaseToPhaseVoltageL2L3());
        voltageDigitalIndicatorL3_L1.setValue(bufferedMultimeterVo.getPhaseToPhaseVoltageL3L1());
        frequency.setValue(bufferedMultimeterVo.getFrequency() / 10.0);

        if (currentL1L2L3ChartEnabled) {
            currentL1L2L3Chart.setL1(bufferedMultimeterVo.getPhaseCurrentL1() / 100);
            currentL1L2L3Chart.setL2(bufferedMultimeterVo.getPhaseCurrentL2() / 100);
            currentL1L2L3Chart.setL3(bufferedMultimeterVo.getPhaseCurrentL3() / 100);
            currentL1L2L3Chart.refreshChart();
        }

        if (voltageL1L2L3ChartEnabled) {
            voltageL1L2L3Chart.setL1(bufferedMultimeterVo.getPhaseVoltageL1());
            voltageL1L2L3Chart.setL2(bufferedMultimeterVo.getPhaseVoltageL2());
            voltageL1L2L3Chart.setL3(bufferedMultimeterVo.getPhaseVoltageL3());
            voltageL1L2L3Chart.refreshChart();
        }

        if (phaseToPhaseL1L2L3ChartEnabled) {
            phaseToPhaseL1L2L3Chart.setL1(bufferedMultimeterVo.getPhaseToPhaseVoltageL1L2());
            phaseToPhaseL1L2L3Chart.setL2(bufferedMultimeterVo.getPhaseToPhaseVoltageL2L3());
            phaseToPhaseL1L2L3Chart.setL3(bufferedMultimeterVo.getPhaseToPhaseVoltageL3L1());
            phaseToPhaseL1L2L3Chart.refreshChart();
        }
    }
}
